﻿using System;
using System.Linq;
using MathService.DSP.Signals;

namespace MathService.DSP
{
    ///<summary>Цифровой фильтр</summary>
    public abstract class DigitalFilter
    {
        /// <summary>Встроенная линия задержки</summary>
        protected DelayLine f_DelayLine;

        /// <summary>Порядок фильтра</summary>        
        public int Order { get { return f_DelayLine.Length; } }


        protected DigitalFilter(int Order) { Initialize(Order); }

        /// <summary>Инициализация начального состояния фильтра</summary>
        public virtual void Initialize() { f_DelayLine.Initialize(); }

        /// <summary>Инициализация фильтра с изменением порядка</summary>
        /// <param name="Order">Порядок фильтра</param>
        protected void Initialize(int Order)
        {
            f_DelayLine = new DelayLine(Order);
        }

        /// <summary>Обработка сигнала</summary>
        /// <param name="x">Входное воздействие в виде отсчётов сигнала</param>
        /// <returns>Массив отсчётов отклика фильтра</returns>        
        public double[] ProcessSignal(double[] x) { return x.Select(Process).ToArray(); }

        /// <summary>обработка входного воздействия в виде цифрового сигнала</summary>
        /// <param name="s">Входное воздействия в виде цифрового сигнала</param>
        /// <returns>Отклик фильтра в виде цифрового сигнала</returns>
        public virtual DigitalSignal ProcessSignal(DigitalSignal s)
        {
            return new DigitalSignal(s.dx, s.x0, s.Length, t => Process(s[t]));
        }

        /// <summary>Получить импульсную характеристику фильтра</summary>
        /// <param name="dt">Период дискретизации сигнала</param>
        /// <param name="Length">Длительность сигнала</param>
        /// <returns>Импульсная характеристика фильтра</returns>
        public DigitalSignal GetImpulseResponse(double dt, double Length)
        {
            var lv_DeltaFunction = DigitalSignal.Standart.DeltaFunction(dt, Length);
            var lv_Line = f_DelayLine;
            f_DelayLine = new DelayLine(f_DelayLine.Length);
            var lv_ImpulsCharactrristic = ProcessSignal(lv_DeltaFunction);
            f_DelayLine = lv_Line;
            return lv_ImpulsCharactrristic;
        }

        public double[] GetImpulseResponse(int Length)
        {
            var lv_DelayLine = f_DelayLine;
            f_DelayLine = new DelayLine(lv_DelayLine.Length);
            var h = new double[Length];
            h[0] = 1;
            var values = h.Initialize(i => Process(h[i]));
            f_DelayLine = lv_DelayLine;
            return values;
        }

        public DigitalSignal GetTransientResponse(double dt, int Length)
        {
            return ProcessSignal(new DigitalSignal(dt, new double[Length].Initialize(i => 1)));
        }

        public abstract double Process(double x_n);

        public abstract Complex TransferFunction(double f, double dt);

        public static ParallelConnectedFilter operator +(DigitalFilter f1, DigitalFilter f2)
        {
            return new ParallelConnectedFilter(f1, f2);
        }

        public static SiquentalConnectedFilter operator *(DigitalFilter f1, DigitalFilter f2)
        {
            return new SiquentalConnectedFilter(f1, f2);
        }
    }

    public class ParallelConnectedFilter : DigitalFilter
    {
        private readonly DigitalFilter f_F1;
        private readonly DigitalFilter f_F2;

        public ParallelConnectedFilter(DigitalFilter f1, DigitalFilter f2)
            : base(0)
        {
            f_F1 = f1;
            f_F2 = f2;
            f_DelayLine = null;
        }

        public override double Process(double x_n)
        {
            return f_F1.Process(x_n) + f_F2.Process(x_n);
        }

        public override Complex TransferFunction(double f, double dt)
        {
            throw new NotImplementedException();
        }
    }

    public class SiquentalConnectedFilter : DigitalFilter
    {
        private readonly DigitalFilter f_F1;
        private readonly DigitalFilter f_F2;

        public SiquentalConnectedFilter(DigitalFilter f1, DigitalFilter f2)
            : base(0)
        {
            f_F1 = f1;
            f_F2 = f2;
            f_DelayLine = null;
        }

        public override double Process(double x_n)
        {
            return f_F2.Process(f_F1.Process(x_n));
        }

        public override Complex TransferFunction(double f, double dt)
        {
            throw new NotImplementedException();
        }
    }

}